/*******************************************************************************
 * StandardAudioLibrary.cpp
 *
 * Copyright (c) 2012, Varuna L Amachi. All rights reserved.
 *
 * This program/library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This program/library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301  USA
 ******************************************************************************/

#include "StandardAudioLibrary.h"
#include "core/manager/T.h"
#include "core/utils/Utils.h"
#include "core/model/MediaItem.h"

#include <QSize>
#include <QFont>

using namespace Tanyatu;

using namespace Component;

QString StandardAudioLibrary::COMPONENT_NAME =
        QString( "Tanyatu::Component::StandardAudioLibrary" );

QString StandardAudioLibrary::COMPONENT_MODULE = QString( "Tanyatu::Core" );

StandardAudioLibrary::StandardAudioLibrary( QObject *parent ) :
    AbstractAudioLibrary( parent ),
    m_itemList( new QList< Model::StoredAudio *>() ),
    m_valid( false )
{
}


bool StandardAudioLibrary::init()
{
    bool result = false;
    if( DATA_RETRIEVER()->getStoredAudio( m_tracks )) {
        QHash< QString, Model::StoredAudio *>::iterator it = m_tracks.begin();
        m_itemList->clear();
        for( ; it != m_tracks.end(); ++ it ) {
            m_itemList->append( it.value() );
        }
        m_valid = true;
        result = true;
        emit libraryChanged();
    }
    return result;
}

void StandardAudioLibrary::add( Model::StoredAudio *item )
{
    if( item && ! m_tracks.contains( item->trackId() )) {
        beginInsertRows( QModelIndex(),
                         m_tracks.size(),
                         m_tracks.size() + 1 );
        m_tracks.insert( item->id(), item );
        m_itemList->append( item );
        emit itemAdded( item );
        endInsertRows();
        emit libraryChanged();
    }
}

void StandardAudioLibrary::add( QList< Tanyatu::Model::StoredAudio *> &items )
{
    if( ! items.empty() ) {
        QList< Model::StoredObject *> storedList;
        beginInsertRows( QModelIndex(),
                         m_tracks.size(),
                         ( m_tracks.size() + items.size() ));
        foreach( Model::StoredAudio *track, items ) {
            if( ! m_tracks.contains( track->id() )) {
                m_tracks.insert( track->id(), track );
                storedList.append( track );
                m_itemList->append( track );
                emit itemAdded( track );
            }
        }
        emit libraryChanged();
        endInsertRows();
    }
}


void StandardAudioLibrary::remove( QString id )
{
    Model::StoredAudio *track = m_tracks.value( id );
    if( track ) {
        int index = m_itemList->indexOf( track );
        beginRemoveRows( QModelIndex(), index, index );
        emit aboutToRemoveItem( track );
        m_tracks.remove( id );
        m_itemList->removeAt( index );
        emit itemRemoved( id );
        delete track;
        endRemoveRows();
        emit libraryChanged();
    }
}

void StandardAudioLibrary::remove( QList< QString > ids )
{
    bool atleastOneRemoved = false;
    foreach( QString id, ids ) {
        Model::StoredAudio *track = item( id );
        if( track ) {
            int index = m_itemList->indexOf( track );
            beginRemoveRows( QModelIndex(), index, index );
            emit aboutToRemoveItem( track );
            m_tracks.remove( id );
            m_itemList->removeAt( index );
            emit itemRemoved( id );
            delete track;
            atleastOneRemoved = true;
            endRemoveRows();
        }
    }
    if( atleastOneRemoved ) {
        emit libraryChanged();
    }
}


void StandardAudioLibrary::rescan()
{
    //Not my job really
}


void StandardAudioLibrary::setRating( QString id,
                                      Tanyatu::Model::MediaRating rating )
{
    beginResetModel();
    Model::StoredAudio *track = m_tracks.value( id );
    if( track ) {
        track->setRating( rating );
        endResetModel();
        emit itemChanged( track );
    }
}


void StandardAudioLibrary::updateItem( QString id,
                                       Tanyatu::Model::AudioTrack &updateInfo )
{
    Model::StoredAudio *track = m_tracks.value( id );
    if( track ) {
        beginResetModel();
        track->setMetadata( updateInfo.title(),
                            updateInfo.artist(),
                            updateInfo.album(),
                            updateInfo.date(),
                            updateInfo.genre(),
                            updateInfo.descreption(),
                            updateInfo.trackNumber(),
                            updateInfo.duration(),
                            updateInfo.bitRate(),
                            updateInfo.sampleRate(),
                            updateInfo.channels() );
        endResetModel();
        emit itemChanged( track );
    }
}


void StandardAudioLibrary::onItemPlaybackStarted(
        Tanyatu::Model::MediaItem *item )
{
    if( item && item->type() == Model::Media_StoredAudio ) {
        Model::StoredAudio *track = dynamic_cast< Model::StoredAudio *>( item );
        track->setPlayCount( track->playCount() + 1 );
        emit itemChanged( track );
    }
}


void StandardAudioLibrary::onItemPlaybackFinished(
        Tanyatu::Model::MediaItem *item )
{
    Q_UNUSED( item );
}


void StandardAudioLibrary::tagItem( QString id, QString tag )
{
    Model::StoredAudio *track = m_tracks.value( id );
    if( track ) {
        track->addTag( tag );
        emit itemChanged( track );
    }
}

void StandardAudioLibrary::removeItemTag( QString id, QString tag )
{
    Model::StoredAudio *track = m_tracks.value( id );
    if( track ) {
        track->removeTag( tag );
        emit itemChanged( track );
    }
}

void StandardAudioLibrary::deleteAll()
{
    clear();
}


StandardAudioLibrary::~StandardAudioLibrary()
{
    clear();
}


quint32 StandardAudioLibrary::itemCount() const
{
    return m_tracks.size();
}

bool StandardAudioLibrary::hasItem( const QString itemId )
{
    return m_tracks.contains( itemId );
}


Model::StoredAudio *StandardAudioLibrary::item( QString id ) const
{
    return m_tracks.value( id );
}


quint32 StandardAudioLibrary::items( QList< QString > &ids,
                        QHash< QString, Model::StoredAudio *> &itemsOut ) const
{
    quint32 itemCount = 0;
    foreach( QString trackId, ids ) {
        Model::StoredAudio *track = m_tracks.value( trackId );
        if( track ) {
            itemsOut.insert( track->id(), track );
            ++ itemCount;
        }
    }
    return itemCount;
}


quint32 StandardAudioLibrary::items( QList< QString > &ids,
                                  QList< Model::MediaItem *> &itemsOut ) const
{
    quint32 itemCount = 0;
    foreach( QString trackId, ids ) {
        Model::StoredAudio *track = m_tracks.value( trackId );
        if( track ) {
            itemsOut.append( track );
            ++ itemCount;
        }
    }
    return itemCount;
}


quint32 StandardAudioLibrary::items(QList<QString> &ids,
                         QList<Tanyatu::Model::StoredAudio *> &itemsOut) const
{
    quint32 itemCount = 0;
    foreach( QString trackId, ids ) {
        Model::StoredAudio *track = m_tracks.value( trackId );
        if( track ) {
            itemsOut.append( track );
            ++ itemCount;
        }
    }
    return itemCount;
}


Model::StoredAudio *StandardAudioLibrary::item( int index ) const
{
    if( index < m_itemList->size() ) {
        return m_itemList->at( index );
    }
    return 0;
}

quint32 StandardAudioLibrary::allItems( QList<Model::StoredAudio *> &out ) const
{
    out.append( m_tracks.values() );
    return out.size();
}


int StandardAudioLibrary::rowCount( const QModelIndex &parent ) const
{
    Q_UNUSED( parent );
    return m_itemList->size();
}


int StandardAudioLibrary::columnCount( const QModelIndex &parent ) const
{
    Q_UNUSED( parent );
    return 5;
}


QVariant StandardAudioLibrary::data( const QModelIndex &index, int role ) const
{
    if( ! index.isValid() || index.row() >= m_tracks.size() ) {
        return QVariant();
    }
    if ( role == Qt::TextAlignmentRole ) {
        return int ( Qt::AlignLeft | Qt::AlignVCenter );
    }
    else if ( role == Qt::DisplayRole ) {
        Model::StoredAudio *source = m_itemList->at( index.row() );
        switch( index.column() ) {
        case 0: return source->id();
        case 1: return source->title();
        case 2: return source->artist();
        case 3: return source->album();
        case 4: return int( source->rating() );
        }
    }
    else if( role == Qt::ToolTipRole ) {
        Model::StoredAudio *source = m_itemList->at( index.row() );
        QString tooltip = QString() +
                tr( "Title  : <b>" ) + source->title()  + "</b><br>" +
                tr( "Artist : <b>" ) + source->artist() + "</b><br>" +
                tr( "Album  : <b>" ) + source->album()  + "</b>" ;
        return tooltip;
    }
    //??
    else if( role == Qt::SizeHintRole ) {
        return QSize( 0, 18 );
    }
    return QVariant();
}


QVariant StandardAudioLibrary::headerData( int section,
                                           Qt::Orientation orientation,
                                           int role ) const
{
    Q_UNUSED( orientation )
    if ( role == Qt::TextAlignmentRole ) {
        return int( Qt::AlignLeft | Qt::AlignVCenter );
    }
    else if ( role == Qt::DisplayRole ) {
        switch( section ) {
        case 0: return tr( "Id" );
        case 1: return tr( "Title" );
        case 2: return tr( "Artist" );
        case 3: return tr( "Album" );
        case 4: return tr( "Rating" );
        }
    }
    return QVariant();
}


QModelIndex StandardAudioLibrary::index( int row, int column,
                                         const QModelIndex &parent ) const
{
    Q_UNUSED( parent )
    return createIndex(row, column);
}


QModelIndex StandardAudioLibrary::parent( const QModelIndex &child ) const
{
    Q_UNUSED( child )
    return QModelIndex();
}


bool StandardAudioLibrary::hasChildren( const QModelIndex &parent ) const
{
    if(! parent.isValid()) {
        return true;
    }
    return false;
}


Qt::ItemFlags StandardAudioLibrary::flags( const QModelIndex &index ) const
{
    Qt::ItemFlags flags = QAbstractItemModel::flags( index );
    if( index.column() == 4 ) {
        return flags |= Qt::ItemIsEditable;
    }
    return flags;
}


bool StandardAudioLibrary::setData( const QModelIndex &index,
                                    const QVariant &value,
                                    int role )
{
    Q_UNUSED( role );
    if( index.column() == 4 ) {
        Model::StoredAudio *item = m_itemList->at( index.row() );
        setRating( item->id(), Utils::getRatingFromInt( value.toInt() ));
        return true;
    }
    return false;
}


void StandardAudioLibrary::setValid( bool value )
{
    m_valid = value;
}


QString StandardAudioLibrary::uniqueName() const
{
    return COMPONENT_NAME;
}


QString StandardAudioLibrary::module() const
{
    return COMPONENT_MODULE;
}


QString StandardAudioLibrary::displayName() const
{
    return tr("Audio Library");
}


void StandardAudioLibrary::clear()
{
    if( m_valid ) {
        emit aboutToClear();
        beginResetModel();
        foreach( Model::MediaItem *track, ( *m_itemList )) {
            delete track;
        }
        m_itemList->clear();
        m_tracks.clear();
        endResetModel();
        emit cleared();
        emit libraryChanged();
    }
}
